local skynet = require "skynet"
local strpack = require "struct".pack
local strunpack = require "struct".unpack
local big = require("bignum")
local bit32 = require("bit32")
-- test ok
local function _get_int1(data, i, is_signed)
  i = i or 1
  local format = is_signed and "b" or "B"
  local value = strunpack(format, data, i)
  return value, i + 1
end

local function _get_byte2(data, i)
  i = i or 1
  local value = strunpack("<H", data, i) -- 'H' 表示2字节无符号整数
  return value, i + 2
end

local function _get_int2(data, i, is_signed)
  local fmt = is_signed and "<h" or "<H"
  return strunpack(fmt, data, i)
end


local function _get_int3(data, i, is_signed)
  i = i or 1
  local bytes = data:sub(i, i + 2)

  if is_signed then
    local sign = bytes:byte(3) >= 0x80 and "\xFF" or "\x00"
    local packed = bytes .. sign
    local value = strunpack("<i4", packed)
    return value, i + 3
  else
    local packed = bytes .. "\x00"
    local value = strunpack("<I4", packed)
    if value > 0x7FFFFF then
      value = value - 0x1000000
    end
    return value, i + 3
  end
end


local function _get_byte4(data, i)
  i = i or 1
  local value, next_pos = strunpack("<I", data, i)
  return value, next_pos
end


local function _get_int4(data, i, is_signed)
  local fmt = is_signed and "<i" or "<I"
  return strunpack(fmt, data, i)
end


local function test_get_int4()
  local test_cases = {
    -- 无符号测试
    { data = "\x00\x00\x00\x00", signed = false, expect = 0 },          -- 最小无符号
    { data = "\xFF\xFF\xFF\xFF", signed = false, expect = 4294967295 }, -- 最大无符号
    { data = "\x01\x00\x00\x00", signed = false, expect = 1 },          -- 典型无符号
    { data = "\x00\x00\x01\x00", signed = false, expect = 65536 },      -- 无符号边界

    -- 有符号测试
    { data = "\xFF\xFF\xFF\x7F", signed = true,  expect = 2147483647 },  -- 最大有符号
    { data = "\x00\x00\x00\x80", signed = true,  expect = -2147483648 }, -- 最小有符号
    { data = "\xFF\xFF\xFF\xFF", signed = true,  expect = -1 },          -- -1
    { data = "\xFE\xFF\xFF\xFF", signed = true,  expect = -2 }           -- -2
  }

  local pos = 1
  for i, case in ipairs(test_cases) do
    local val, new_pos = _get_int4(case.data, 1, case.signed)
    assert(val == case.expect,
      string.format("Test %d failed: got %d, expect %d", i, val, case.expect))
    pos = new_pos
    print(string.format("Test %d passed: %s value %d == expect %d",
      i, case.signed and "signed" or "unsigned", val, case.expect))
  end
end

local function _from_cstring(data, i)
  i = i or 1
  local len = #data
  local bytes = {}
  local idx = i

  while idx <= len do
    local b = string.byte(data, idx)
    if b == 0 then
      break
    end
    table.insert(bytes, b)
    idx = idx + 1
  end

  local str = string.char(table.unpack(bytes))
  return str, idx + 1 -- 跳过 '\0'
end

local function _get_int8(data, i, is_signed)
  i = i or 1
  local b1, b2, b3, b4, b5, b6, b7, b8 = string.byte(data, i, i + 7)

  local unsigned_val =
      b1 + b2 * 256 + b3 * 65536 + b4 * 16777216 +
      b5 * 4294967296 + b6 * 1099511627776 +
      b7 * 281474976710656 + b8 * 72057594037927936

  if is_signed and b8 >= 0x80 then
    return unsigned_val - 0x10000000000000000, i + 8
  else
    return unsigned_val, i + 8
  end
end


local function _get_float(data, i)
  return strunpack("f", data, i)
end

local function _get_double(data, i)
  return strunpack("d", data, i)
end

local function _set_byte2(n)
  return strpack("H", n)
end


local function test_int8()
  local samples = {
    { name = "zero", bytes = "\x00\x00\x00\x00\x00\x00\x00\x00" },
    { name = "max unsigned", bytes = "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" },
    { name = "max signed", bytes = "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F" },
    { name = "min signed", bytes = "\x00\x00\x00\x00\x00\x00\x00\x80" },
    { name = "random", bytes = "8.0.41s}%?'l/@�����(JVU)H6\"..caching_sha2_passwor" },
  }

  for _, s in ipairs(samples) do
    local signed = _get_int8(s.bytes, 1, true)
    local unsigned = _get_int8(s.bytes, 1, false)
    print(string.format("[int8] %-13s => signed: %s, unsigned: %s", s.name, tostring(signed), tostring(unsigned)))
  end
end


local function _set_byte2(n)
  return strpack("<I2", n)
end

local function test_float_double()
  local values = { 0.0, 1.0, -1.5, 123.456, math.huge, -math.huge, 0 / 0 }

  for _, v in ipairs(values) do
    local fpacked = strpack("f", v)
    local dpacked = strpack("d", v)

    local fread = _get_float(fpacked, 1)
    local dread = _get_double(dpacked, 1)

    print(string.format("float  input: %-10s => unpacked: %-10s", tostring(v), tostring(fread)))
    print(string.format("double input: %-10s => unpacked: %-10s", tostring(v), tostring(dread)))
    print("---")
  end
end


local function test_byte2()
  local inputs = { 0, 1, 300, 65535 }
  for _, n in ipairs(inputs) do
    local packed = _set_byte2(n)
    local b1, b2 = string.byte(packed, 1, 2)
    print(string.format("value: %-5d => bytes: %02X %02X", n, b1, b2))
  end
end

local function bytes_to_hex(s)
  return (s:gsub('.', function(c) return string.format('%02X ', string.byte(c)) end))
end


local function assert_equal(actual, expected, desc)
  if actual ~= expected then
    error(("FAIL: %s\nExpected: %s\nGot     : %s"):format(desc, tostring(expected), tostring(actual)))
  else
    print("PASS:", desc)
  end
end


local function test__from_cstring_advanced()
  print(">> Testing _from_cstring...")

  -- 1. 基本读取
  local s1 = "hello\0"
  local v1, i1 = _from_cstring(s1, 1)
  assert_equal(v1, "hello", "Case 1: Basic C-string")
  assert_equal(i1, 7, "Case 1: Next index")

  -- 2. 多段拼接
  local s2 = "hello\0world\0bye\0"
  local v2a, i2a = _from_cstring(s2, 1)
  assert_equal(v2a, "hello", "Case 2a: First string")
  local v2b, i2b = _from_cstring(s2, i2a)
  assert_equal(v2b, "world", "Case 2b: Second string")
  local v2c, i2c = _from_cstring(s2, i2b)
  assert_equal(v2c, "bye", "Case 2c: Third string")
  assert_equal(i2c, #s2 + 1, "Case 2c: End index")

  -- 3. 空字符串开头
  local s3 = "\0abc\0"
  local v3a, i3a = _from_cstring(s3, 1)
  assert_equal(v3a, "", "Case 3a: Empty string")
  local v3b, i3b = _from_cstring(s3, i3a)
  assert_equal(v3b, "abc", "Case 3b: abc after empty")

  -- 4. 连续两个空字符串
  local s4 = "\0\0xyz\0"
  local v4a, i4a = _from_cstring(s4, 1)
  assert_equal(v4a, "", "Case 4a: First empty")
  local v4b, i4b = _from_cstring(s4, i4a)
  assert_equal(v4b, "", "Case 4b: Second empty")
  local v4c, i4c = _from_cstring(s4, i4b)
  assert_equal(v4c, "xyz", "Case 4c: 'xyz' after empties")

  -- 5. 包含二进制字符（不可见字符）
  local s5 = "\1\2\3\4\5\0next\0"
  local v5, i5 = _from_cstring(s5, 1)
  assert_equal(bytes_to_hex(v5), "01 02 03 04 05 ", "Case 5: Binary string content")
  local v5b, _ = _from_cstring(s5, i5)
  assert_equal(v5b, "next", "Case 5b: Second string after binary")


  -- 6. 从中间读取（偏移）
  local s7 = "abc\0def\0"
  local _, mid = _from_cstring(s7, 1)
  local val7, idx7 = _from_cstring(s7, mid)
  assert_equal(val7, "def", "Case 7: Offset read")

  print(">> All _from_cstring tests passed!")
end

skynet.start(function()
  skynet.error("Starting comprehensive struct tests...")

  local data = "8.0.41s}%?'l/@�����(JVU)H6\"..caching_sha2_passwor"


  -- local test_cases = {
  --   { desc = "zero",         bytes = "\x00\x00\x00" },
  --   { desc = "negative one", bytes = "\xFF\xFF\xFF" },
  --   { desc = "positive one", bytes = "\x01\x00\x00" },
  --   { desc = "min signed",   bytes = "\x00\x00\x80" },
  --   { desc = "max signed",   bytes = "\xFF\xFF\x7F" },
  -- }

  -- for _, case in ipairs(test_cases) do
  --   local signed, _ = _get_int3(case.bytes, 1, true)
  --   local unsigned, _ = _get_int3(case.bytes, 1, false)
  --   print(string.format("[%-12s] signed: %d, unsigned: %d", case.desc, signed, unsigned))
  -- end
  -- test_get_int4()


  --test_int8()
  --test_float_double()
  --test_byte2()

  test__from_cstring_advanced()

  skynet.error("All struct tests passed successfully!")
  skynet.exit()
end)
